package org.colcon.web.model;

import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.colcon.web.model.decision.NullDecision;
import org.colcon.web.model.framework.IBallot;
import org.colcon.web.model.framework.IDecision;
import org.colcon.web.model.framework.IUser;
import org.colcon.web.model.framework.IVote;

public class Vote extends Container implements IVote
{
	private static final long serialVersionUID = 5206645418694019354L;
	
	public static final String

		// arguments
		GROUP = "group",
		LENGTH = "length",
		QUORUM = "quorum",
		TITLES = "titles",
	
		// containers
		BALLOTS = "ballots";
	
	private String group;
	
	/** full paths to required titles */
	private Set<String> requiredTitles;
	
	private int quorum, length;
	
	public Vote()
	{
		this(new HashMap<String, String>());
	}
	
	public Vote(Map<String, String> args)
	{
		//TODO: add vote_type argument
		this(
				args.get(ID), 
				args.get(GROUP), 
				Integer.valueOf(args.get(LENGTH)), 
				Integer.valueOf(args.get(QUORUM)), 
				args.get(TITLES)
		);
	}
	
	public Vote(String id, String group, int length, int quorum, String titles)
	{
		this(id, group, length, quorum, titles.split(" "));
	}
	
	public Vote(String id, String group, int length, int quorum, String[] titles)
	{
		super(id);
		
		addContainer(BALLOTS);
		
		this.group = group;
		this.length = length;
		this.quorum = quorum;
		
		requiredTitles = new HashSet<String>();
		
		if(titles != null)
			for(String str : titles)
				requiredTitles.add(str);
	}
	
	public String getGroup()
	{
		return group;
	}
	
	public int getLength()
	{
		return length;
	}
	
	public int getQuorum()
	{
		return quorum;
	}
	
	public String[] getRequiredTitles()
	{
		return requiredTitles.toArray(new String[0]);
	}
	
	public IBallot[] getBallots()
	{
		return getGrandChildren(BALLOTS).toArray(new IBallot[0]);
	}
	
	public IBallot getBallot(String id)
	{
		return (IBallot) get(BALLOTS, id);
	}
	
	public boolean hasBallot(String id)
	{
		return has(BALLOTS, id);
	}
	
	public IBallot vote(IUser user, String vote)
	{
		if(!isEligible(user))
			return null;
		
		IBallot ballot = new Ballot(getPath(), user.getId(), vote);
		
		add(BALLOTS, ballot);
		
		return ballot;
	}
	
	public IDecision getResult()
	{
		IDecision result = new NullDecision(group);
		
		if(getBallots().length >= quorum)
			result = getResult();
		
		return result;
	}
	
	public boolean isEligible(IUser user)
	{
		for(String str : requiredTitles)
			if(!user.hasTitle(str))
				return false;
		
		// ballots stored by voter id
		if(hasBallot(user.getId()))
			return false;
		
		return true;
	}
	
	public Date getEndDate()
	{
		return Model.addToDate(getDate(), getLength());
	}
	
	public boolean isOver()
	{
		return new Date().after(getEndDate());
	}
	
	public String getText()
	{
		return getId();
	}
	public IDecision getDecision()
	{
		return new NullDecision(group);
	}
}
